using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Transactions;
using HengTong.Model.Db.Hr;
using HengTong.Model.Db.Hr.Attendance;
using HengTong.Model.Db.Hr.Bill;
using HengTong.Model.Request;
using HengTong.ViewModel.Daily.SysDailyCompOffRequestBillVms;
using HengTong.ViewModel.Daily.SysDailyLeaveRequestBillVms;
using HengTong.ViewModel.Daily.SysDailyOvertimeRequestBillVms;
using HengTong.ViewModel.Daily.SysDailyShiftSwapRequestBillVms;
using HengTong.ViewModel.Daily.SysDailySubstitutionRequestBillVms;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using WalkingTec.Mvvm.Core.Extensions;


namespace HengTong.ViewModel.Hr.SysAttendanceRecordVms
{
    public partial class SysAttendanceRecordBatchVm
    {
        /// <summary>
        /// 人工排班
        /// </summary>
        /// <param name="request"></param>
        /// <param name="scheduleType">排班类型, 仅在流程完成后调用</param>
        /// <param name="billId">当排班类型是流程排班的时候必须传入对应的申请单ID</param>
        /// <returns></returns>
        public async Task<bool> DoBatchAddAsync(AddAttendanceRecordsRequest request,
            ScheduleTypeEnum? scheduleType = null, Guid? billId = null)
        {
            if (request.PersonIds == null || request.PersonIds.Length == 0)
            {
                MSD.AddModelError(" ", "请选择人员");
                return false;
            }

            if (request.DateRange == null || request.DateRange.GetStartTime() == null ||
                request.DateRange.GetEndTime() == null)
            {
                MSD.AddModelError(" ", "请选择排班日期");
                return false;
            }

            if (request.ShiftType == ShiftAction.替班 && request.SubstitutePersonId == null)
            {
                MSD.AddModelError(" ", "替班必须选择替班人员");
                return false;
            }

            if (scheduleType == ScheduleTypeEnum.流程排班)
            {
                if (billId == null)
                {
                    MSD.AddModelError(" ", "流程排班必须传入申请单ID");
                    return false;
                }

                if (request.ShiftType == ShiftAction.请假 || request.ShiftType == ShiftAction.出差)
                {
                    var bill = await DC.Set<SysDailyLeaveRequestBill>()
                        .AsNoTracking()
                        .FirstOrDefaultAsync(e => e.ID == billId.Value);
                    if (bill == null)
                    {
                        MSD.AddModelError(" ", "请假出差申请单不存在");
                        return false;
                    }
                }
                else if (request.ShiftType == ShiftAction.调休)
                {
                    var bill = await DC.Set<SysDailyCompOffRequestBill>()
                        .AsNoTracking()
                        .FirstOrDefaultAsync(e => e.ID == billId.Value);
                    if (bill == null)
                    {
                        MSD.AddModelError(" ", "调休申请单不存在");
                        return false;
                    }
                }
                else if (request.ShiftType == ShiftAction.替班)
                {
                    var bill = await DC.Set<SysDailySubstitutionRequestBill>()
                        .AsNoTracking()
                        .FirstOrDefaultAsync(e => e.ID == billId.Value);
                    if (bill == null)
                    {
                        MSD.AddModelError(" ", "替班申请单不存在");
                        return false;
                    }
                }
                else if (request.ShiftType == ShiftAction.换班)
                {
                    var bill = await DC.Set<SysDailyShiftSwapRequestBill>()
                        .AsNoTracking()
                        .FirstOrDefaultAsync(e => e.ID == billId.Value);
                    if (bill == null)
                    {
                        MSD.AddModelError(" ", "换班申请单不存在");
                        return false;
                    }
                }
                else if (request.ShiftType == ShiftAction.加班)
                {
                    // 因为都需要读取单据, 所以校验放到业务中进行, 降低性能损耗
                }
                else
                {
                    MSD.AddModelError(" ", "不支持的流程排班类型");
                    return false;
                }
            }

            if (scheduleType != ScheduleTypeEnum.流程排班) scheduleType = ScheduleTypeEnum.人工排班;
            var scope = Wtm.ServiceProvider.CreateScope();
            var logger = scope.ServiceProvider
                .GetRequiredService<Microsoft.Extensions.Logging.ILogger<SysAttendanceRecordBatchVm>>();
            // 从排班日期开始循环, 每次循环加一天, 最多截止当前日期的90天
            var startDate = DateOnly.FromDateTime(request.DateRange.GetStartTime().Value);
            var endDate = DateOnly.FromDateTime(request.DateRange.GetEndTime().Value).AddDays(-1);
            if (request.AutoCalculateFuture)
            {
                endDate = DateOnly.FromDateTime(DateTime.Now.AddDays(90));
            }

            if (request.ShiftType == ShiftAction.请假 || request.ShiftType == ShiftAction.调休 ||
                request.ShiftType == ShiftAction.出差)
            {
                ShiftTypeEnum action = ShiftTypeEnum.请假;
                if (request.ShiftType == ShiftAction.请假) action = ShiftTypeEnum.请假;
                if (request.ShiftType == ShiftAction.调休) action = ShiftTypeEnum.调休;
                if (request.ShiftType == ShiftAction.出差) action = ShiftTypeEnum.出差;
                foreach (var personId in request.PersonIds)
                {
                    // 读取排班日期以后所有的排班记录, 如果是自动排班则读取未来90天的排班记录, 否则只读取排班日期到结束日期的排班记录
                    var existingRecords = await DC.Set<SysAttendanceRecord>()
                        .AsNoTracking()
                        .Include(e => e.Person)
                        .Where(x => x.PersonId == personId)
                        .Where(x => x.ShiftDate >= startDate)
                        .WhereIf(!request.AutoCalculateFuture, x => x.ShiftDate <= endDate)
                        .Where(x => x.Status == ShiftStatusEnum.正常)
                        .ToListAsync();
                    var updateRecordIds = new List<Guid>();
                    string person = null;
                    for (var date = startDate; date <= endDate; date = date.AddDays(1))
                    {
                        var record = existingRecords.FirstOrDefault(x => x.ShiftDate == date);
                        if (record != null)
                        {
                            person = record.Person?.Name;
                            // 如果排班已经有考勤结果, 则抛出异常
                            if (record.AttendanceResult != AttendanceResultEnum.未计算)
                            {
                                MSD.AddModelError(" ", $"人员{person}在{date}的排班已经有考勤结果, 无法修改考勤组");
                                return false;
                            }
                            else
                            {
                                // 如果没有考勤结果, 则更新考勤组
                                updateRecordIds.Add(record.ID);
                                record.ShiftType = action;
                            }
                        }
                        else
                        {
                            MSD.AddModelError(" ", $"人员{person ?? personId.ToString()}没有排班记录, 只能对已有排班记录进行请假、出差或调休操作");
                            return false;
                        }
                    }

                    // 批量更新排班记录
                    if (updateRecordIds.Count > 0)
                    {
                        await DC.Set<SysAttendanceRecord>()
                            .Where(e => updateRecordIds.Contains(e.ID))
                            .ExecuteUpdateAsync(e => e
                                .SetProperty(r => r.ShiftType, r => action)
                                .SetProperty(r => r.ScheduleType, r => scheduleType)
                                .SetProperty(r => r.Remark, r => request.Remark)
                                .SetProperty(r => r.UpdateTime, r => DateTime.Now)
                                .SetProperty(r => r.UpdateBy, r => Wtm.LoginUserInfo.ITCode)
                                .SetProperty(r => r.BillId, billId)
                            );
                    }
                }
            }

            if (request.ShiftType == ShiftAction.换班)
            {
                if (request.SwapShiftId == null)
                {
                    MSD.AddModelError(" ", "换班必须选择换班关联");
                    return false;
                }

                if (request.PersonIds.Length != 1)
                {
                    MSD.AddModelError(" ", "换班仅允许单人操作");
                    return false;
                }

                var personId = request.PersonIds[0];
                // 交换换班信息
                var swap = await DC.Set<SysAttendanceRecord>()
                    .AsNoTracking()
                    .Include(e => e.Person)
                    .Where(x => x.ID == request.SwapShiftId)
                    .FirstOrDefaultAsync();
                if (swap == null)
                {
                    MSD.AddModelError(" ", "换班关联不存在");
                    return false;
                }

                if (swap.PersonId == personId)
                {
                    MSD.AddModelError(" ", "换班关联不能是同一个人");
                    return false;
                }

                if (swap.AttendanceResult != AttendanceResultEnum.未计算)
                {
                    MSD.AddModelError(" ", $"人员{swap.Person?.Name}在{swap.ShiftDate}的排班已经有考勤结果, 无法修改考勤组");
                    return false;
                }

                if (swap.ShiftType != ShiftTypeEnum.正常上班)
                {
                    MSD.AddModelError(" ", $"人员{swap.Person?.Name}在{swap.ShiftDate}的排班为:{swap.ShiftType}, 无法换班");
                    return false;
                }

                // 读取排班日期以后所有的排班记录, 如果是自动排班则读取未来90天的排班记录, 否则只读取排班日期到结束日期的排班记录
                var record = await DC.Set<SysAttendanceRecord>()
                    .AsNoTracking()
                    .Include(e => e.Person)
                    .Where(x => x.PersonId == personId)
                    .Where(x => x.ShiftDate == startDate)
                    .Where(x => x.Status == ShiftStatusEnum.正常)
                    .FirstOrDefaultAsync();
                string person = null;
                var date = startDate;
                if (record != null)
                {
                    person = record.Person?.Name;
                    // 如果排班已经有考勤结果, 则抛出异常
                    if (record.AttendanceResult != AttendanceResultEnum.未计算)
                    {
                        MSD.AddModelError(" ", $"人员{person}在{date}的排班已经有考勤结果, 无法修改考勤组");
                        return false;
                    }
                    else
                    {
                        // 在“换班”分支内，把原来的手动事务块替换为如下写法：
                        var hasAmbientTx = Transaction.Current != null || DC.Database.CurrentTransaction != null;
                        IDbContextTransaction? localTx = null;
                        try
                        {
                            if (!hasAmbientTx)
                                localTx = DC.BeginTransaction(); // 只有在没有环境事务时才开启本地事务
                            //更新考勤
                            await DC.Set<SysAttendanceRecord>()
                                .Where(e => e.ID == record.ID)
                                .ExecuteUpdateAsync(e => e
                                    .SetProperty(r => r.ShiftType, r => ShiftTypeEnum.换班)
                                    .SetProperty(r => r.SwapShiftId, r => request.SwapShiftId)
                                    .SetProperty(r => r.ScheduleType, r => scheduleType)
                                    .SetProperty(r => r.Remark, r => request.Remark)
                                    .SetProperty(r => r.UpdateTime, r => DateTime.Now)
                                    .SetProperty(r => r.UpdateBy, r => Wtm.LoginUserInfo.ITCode)
                                    .SetProperty(r => r.BillId, billId)
                                );
                            await DC.Set<SysAttendanceRecord>()
                                .Where(e => e.ID == swap.ID)
                                .ExecuteUpdateAsync(e => e
                                    .SetProperty(r => r.ShiftType, r => ShiftTypeEnum.换班)
                                    .SetProperty(r => r.SwapShiftId, r => record.ID)
                                    .SetProperty(r => r.ScheduleType, r => scheduleType)
                                    .SetProperty(r => r.Remark, r => request.Remark)
                                    .SetProperty(r => r.UpdateTime, r => DateTime.Now)
                                    .SetProperty(r => r.UpdateBy, r => Wtm.LoginUserInfo.ITCode)
                                    .SetProperty(r => r.BillId, billId)
                                );
                            if (localTx != null)
                                await localTx.CommitAsync();

                            record.ShiftType = ShiftTypeEnum.换班;
                        }
                        catch (Exception)
                        {
                            if (localTx != null)
                                await localTx.RollbackAsync();

                            MSD.AddModelError(" ", "换班失败, 请联系信息部门");
                            return false;
                        }
                        finally
                        {
                            if (localTx != null)
                                await localTx.DisposeAsync();
                        }
                    }
                }
                else
                {
                    MSD.AddModelError(" ", $"人员{person ?? personId.ToString()}没有排班记录, 只能对已有排班记录进行换班操作");
                    return false;
                }
            }

            if (request.ShiftType == ShiftAction.替班)
            {
                if (request.SubstitutePersonId == null)
                {
                    MSD.AddModelError(" ", "替班必须选择替班人");
                    return false;
                }

                if (request.PersonIds.Length != 1)
                {
                    MSD.AddModelError(" ", "替班仅允许单人操作");
                    return false;
                }

                var personId = request.PersonIds[0];
                if (personId == request.SubstitutePersonId)
                {
                    MSD.AddModelError(" ", "替班人不能是同一个人");
                    return false;
                }

                // 读取排班日期以后所有的排班记录, 如果是自动排班则读取未来90天的排班记录, 否则只读取排班日期到结束日期的排班记录
                var record = await DC.Set<SysAttendanceRecord>()
                    .AsNoTracking()
                    .Include(e => e.Person)
                    .Where(x => x.PersonId == personId)
                    .Where(x => x.ShiftDate == startDate)
                    .Where(x => x.Status == ShiftStatusEnum.正常)
                    .FirstOrDefaultAsync();
                var subPerson = await DC.Set<SysPerson>()
                    .AsNoTracking()
                    .Where(x => x.GetType() == typeof(SysPerson))
                    .Where(e => e.ID == request.SubstitutePersonId)
                    .FirstOrDefaultAsync();
                if (subPerson == null)
                {
                    MSD.AddModelError(" ", "替换人不存在");
                    return false;
                }

                string person = null;
                var date = startDate;
                if (record != null)
                {
                    person = record.Person?.Name;
                    // 如果排班已经有考勤结果, 则抛出异常
                    if (record.AttendanceResult != AttendanceResultEnum.未计算)
                    {
                        MSD.AddModelError(" ", $"人员{person}在{date}的排班已经有考勤结果, 无法修改考勤组");
                        return false;
                    }
                    else
                    {
                        //更新考勤
                        await DC.Set<SysAttendanceRecord>()
                            .Where(e => e.ID == record.ID)
                            .ExecuteUpdateAsync(e => e
                                .SetProperty(r => r.ShiftType, r => ShiftTypeEnum.替班)
                                .SetProperty(r => r.SubstitutePersonId, r => request.SubstitutePersonId)
                                .SetProperty(r => r.ScheduleType, r => scheduleType)
                                .SetProperty(r => r.Remark, r => request.Remark)
                                .SetProperty(r => r.UpdateTime, r => DateTime.Now)
                                .SetProperty(r => r.UpdateBy, r => Wtm.LoginUserInfo.ITCode)
                                .SetProperty(r => r.BillId, billId)
                            );
                        record.SubstitutePersonId = request.SubstitutePersonId;
                        record.ShiftType = ShiftTypeEnum.换班;
                    }
                }
                else
                {
                    MSD.AddModelError(" ", $"人员{person ?? personId.ToString()}没有排班记录, 只能对已有排班记录进行替班操作");
                    return false;
                }
            }

            if (request.ShiftType == ShiftAction.排班)
            {
                // 循环人员
                foreach (var personId in request.PersonIds)
                {
                    // 读取排班日期以后所有的排班记录, 如果是自动排班则读取未来90天的排班记录, 否则只读取排班日期到结束日期的排班记录
                    var existingRecords = await DC.Set<SysAttendanceRecord>()
                        .AsNoTracking()
                        .Where(x => x.PersonId == personId)
                        .Where(x => x.ShiftDate >= startDate)
                        .WhereIf(!request.AutoCalculateFuture, x => x.ShiftDate <= endDate)
                        .Where(x => x.Status == ShiftStatusEnum.正常)
                        .ToListAsync();

                    var records = new List<SysAttendanceRecord>();
                    var updateRecordIds = new List<Guid>();
                    for (var date = startDate; date <= endDate; date = date.AddDays(1))
                    {
                        var record = existingRecords.FirstOrDefault(x => x.ShiftDate == date);
                        if (record != null)
                        {
                            // 如果排班已经有考勤结果, 则抛出异常
                            if (record.AttendanceResult != AttendanceResultEnum.未计算)
                            {
                                MSD.AddModelError(" ", $"人员{personId}在{date}的排班已经有考勤结果, 无法修改考勤组");
                                return false;
                            }
                            else
                            {
                                // 如果没有考勤结果, 则更新考勤组
                                updateRecordIds.Add(record.ID);
                                record.AttendanceShiftGroupId = request.AttendanceShiftGroupId;
                                if (record.ScheduleType != ScheduleTypeEnum.自动排班)
                                {
                                    if (record.ScheduleType == ScheduleTypeEnum.流程排班)
                                    {
                                        //这里需要失效对应的流程, 并且发送通知
                                        if (record.BillId == null)
                                        {
                                            logger.LogWarning("排班记录{@record}的排班类型为流程排班, 但没有关联单据ID", record);
                                            continue;
                                        }

                                        if (record.ShiftType == ShiftTypeEnum.请假 ||
                                            record.ShiftType == ShiftTypeEnum.出差)
                                        {
                                            var bill = await DC.Set<SysDailyLeaveRequestBill>()
                                                .AsNoTracking()
                                                .FirstOrDefaultAsync(e => e.ID == record.BillId.Value);
                                            if (bill == null)
                                            {
                                                logger.LogWarning("排班记录{@record}关联的请假出差单据不存在", record);
                                                continue;
                                            }

                                            var vm = Wtm.CreateVM<SysDailyLeaveRequestBillVm>(bill.ID);
                                            await vm.CancelWorkflowAsync("重新排班, 流程取消, 如有需要请重新发起申请");
                                        }
                                        else if (record.ShiftType == ShiftTypeEnum.调休)
                                        {
                                            var bill = await DC.Set<SysDailyCompOffRequestBill>()
                                                .AsNoTracking()
                                                .FirstOrDefaultAsync(e => e.ID == record.BillId.Value);
                                            if (bill == null)
                                            {
                                                logger.LogWarning("排班记录{@record}关联的调休单据不存在", record);
                                                continue;
                                            }

                                            var vm = Wtm.CreateVM<SysDailyCompOffRequestBillVm>(bill.ID);
                                            await vm.CancelWorkflowAsync("重新排班, 流程取消, 如有需要请重新发起申请");
                                        }
                                        else if (record.ShiftType == ShiftTypeEnum.替班)
                                        {
                                            var bill = await DC.Set<SysDailySubstitutionRequestBill>()
                                                .AsNoTracking()
                                                .FirstOrDefaultAsync(e => e.ID == record.BillId.Value);
                                            if (bill == null)
                                            {
                                                logger.LogWarning("排班记录{@record}关联的替班单据不存在", record);
                                                continue;
                                            }

                                            var vm = Wtm.CreateVM<SysDailySubstitutionRequestBillVm>(bill.ID);
                                            await vm.CancelWorkflowAsync("重新排班, 流程取消, 如有需要请重新发起申请");
                                        }
                                        else if (record.ShiftType == ShiftTypeEnum.换班)
                                        {
                                            var bill = await DC.Set<SysDailyShiftSwapRequestBill>()
                                                .AsNoTracking()
                                                .FirstOrDefaultAsync(e => e.ID == record.BillId.Value);
                                            if (bill == null)
                                            {
                                                logger.LogWarning("排班记录{@record}关联的换班单据不存在", record);
                                                continue;
                                            }

                                            var vm = Wtm.CreateVM<SysDailyShiftSwapRequestBillVm>(bill.ID);
                                            await vm.CancelWorkflowAsync("重新排班, 流程取消, 如有需要请重新发起申请");
                                        }
                                        else if (record.ShiftType == ShiftTypeEnum.加班)
                                        {
                                            var bill = await DC.Set<SysDailyOvertimeRequestBill>()
                                                .AsNoTracking()
                                                .FirstOrDefaultAsync(e => e.ID == record.BillId.Value);
                                            if (bill == null)
                                            {
                                                logger.LogWarning("排班记录{@record}关联的加班单据不存在", record);
                                                continue;
                                            }

                                            var vm = Wtm.CreateVM<SysDailyOvertimeRequestBillVm>(bill.ID);
                                            await vm.CancelWorkflowAsync("重新排班, 流程取消, 如有需要请重新发起申请");
                                        }
                                        else
                                        {
                                            logger.LogWarning("排班记录{@record}的排班类型为流程排班, 但不支持的流程类型:{type}", record,
                                                request.ShiftType);
                                            continue;
                                        }
                                    }

                                    record.ScheduleType = ScheduleTypeEnum.自动排班;
                                }
                            }
                        }
                        else
                        {
                            // 如果没有排班记录, 则新增一条排班记录
                            record = new SysAttendanceRecord
                            {
                                ID = Guid.NewGuid(),
                                PersonId = personId,
                                ShiftDate = date,
                                AttendanceShiftGroupId = request.AttendanceShiftGroupId,
                                ShiftType = ShiftTypeEnum.正常上班,
                                ScheduleType = ScheduleTypeEnum.自动排班,
                                Status = ShiftStatusEnum.正常,
                                AttendanceResult = AttendanceResultEnum.未计算,
                                IsAbnormal = false,
                                CreateBy = Wtm.LoginUserInfo.ITCode,
                                UpdateBy = Wtm.LoginUserInfo.ITCode,
                                CreateTime = DateTime.Now,
                                UpdateTime = DateTime.Now
                            };
                            records.Add(record);
                        }
                    }

                    // 批量更新排班记录,debug模式下新增前30天的考勤数据
#if DEBUG
                    // 新增前30天的考勤数据, 仅调试使用, 90% 是正常上班, 10%是异常
                    var debugRecords = new List<SysAttendanceRecord>();
                    var random = new Random();
                    var debugStartDate = DateOnly.FromDateTime(request.DateRange.GetStartTime().Value.AddDays(-30));
                    var debugEndDate = DateOnly.FromDateTime(request.DateRange.GetStartTime().Value.AddDays(-1));

                    // 获取前30天已存在的记录
                    var existingDebugRecords = await DC.Set<SysAttendanceRecord>()
                        .AsNoTracking()
                        .Where(x => x.PersonId == personId && x.ShiftDate >= debugStartDate &&
                                    x.ShiftDate <= debugEndDate)
                        .Where(x => x.Status == ShiftStatusEnum.正常)
                        .ToListAsync();

                    for (var debugDate = debugStartDate; debugDate <= debugEndDate; debugDate = debugDate.AddDays(1))
                    {
                        // 如果该日期已有记录，跳过
                        if (existingDebugRecords.Any(x => x.ShiftDate == debugDate))
                            continue;

                        // 生成随机数决定是否为异常记录 (10%概率为异常)
                        var isAbnormal = random.NextDouble() < 0.1;
                        AttendanceResultEnum attendanceResult;
                        int? lateMinutes = null;
                        int? earlyLeaveMinutes = null;
                        int? workMinutes = null;
                        int? missingPunchCount = null;
                        TimeOnly? startTime = null;
                        TimeOnly? endTime = null;

                        // 标准上下班时间 (9:00-18:00)
                        var standardStartTime = new TimeOnly(9, 0);
                        var standardEndTime = new TimeOnly(18, 0);

                        if (isAbnormal)
                        {
                            // 10%异常情况：随机选择迟到、早退、迟到且早退、缺卡、旷工
                            var abnormalResults = new[]
                            {
                                AttendanceResultEnum.迟到,
                                AttendanceResultEnum.早退,
                                AttendanceResultEnum.迟到且早退,
                                AttendanceResultEnum.缺卡,
                                AttendanceResultEnum.旷工
                            };
                            attendanceResult = abnormalResults[random.Next(abnormalResults.Length)];

                            // 根据不同的异常类型生成相应的数据
                            switch (attendanceResult)
                            {
                                case AttendanceResultEnum.迟到:
                                    lateMinutes = random.Next(5, 121); // 5-120分钟迟到
                                    workMinutes = 480 - lateMinutes; // 8小时减去迟到时间
                                    startTime = standardStartTime.AddMinutes(lateMinutes.Value); // 迟到的上班时间
                                    endTime = standardEndTime; // 正常下班时间
                                    break;

                                case AttendanceResultEnum.早退:
                                    earlyLeaveMinutes = random.Next(5, 121); // 5-120分钟早退
                                    workMinutes = 480 - earlyLeaveMinutes; // 8小时减去早退时间
                                    startTime = standardStartTime; // 正常上班时间
                                    endTime = standardEndTime.AddMinutes(-earlyLeaveMinutes.Value); // 早退的下班时间
                                    break;

                                case AttendanceResultEnum.迟到且早退:
                                    lateMinutes = random.Next(5, 61); // 5-60分钟迟到
                                    earlyLeaveMinutes = random.Next(5, 61); // 5-60分钟早退
                                    workMinutes = 480 - lateMinutes - earlyLeaveMinutes; // 8小时减去迟到和早退时间
                                    startTime = standardStartTime.AddMinutes(lateMinutes.Value); // 迟到的上班时间
                                    endTime = standardEndTime.AddMinutes(-earlyLeaveMinutes.Value); // 早退的下班时间
                                    break;

                                case AttendanceResultEnum.缺卡:
                                    missingPunchCount = random.Next(1, 3); // 1-2次缺卡
                                    workMinutes = random.Next(200, 481); // 缺卡情况下工时不确定，200-480分钟
                                    // 缺卡情况随机缺失上班或下班时间
                                    if (random.NextDouble() < 0.5)
                                    {
                                        // 缺上班卡，只有下班时间
                                        startTime = null;
                                        endTime = standardEndTime.AddMinutes(random.Next(-30, 31)); // 下班时间有小幅波动
                                    }
                                    else
                                    {
                                        // 缺下班卡，只有上班时间
                                        startTime = standardStartTime.AddMinutes(random.Next(-15, 31)); // 上班时间有小幅波动
                                        endTime = null;
                                    }

                                    break;

                                case AttendanceResultEnum.旷工:
                                    workMinutes = 0; // 旷工无工时
                                    missingPunchCount = random.Next(2, 5); // 2-4次缺卡
                                    // 旷工情况没有上下班时间
                                    startTime = null;
                                    endTime = null;
                                    break;
                            }
                        }
                        else
                        {
                            // 90%正常情况
                            attendanceResult = AttendanceResultEnum.正常;
                            workMinutes = 480; // 正常8小时工作时间
                            lateMinutes = 0;
                            earlyLeaveMinutes = 0;
                            missingPunchCount = 0;
                            // 正常情况的上下班时间有小幅随机波动(-5到+5分钟)
                            startTime = standardStartTime.AddMinutes(random.Next(-5, 6));
                            endTime = standardEndTime.AddMinutes(random.Next(-5, 6));
                        }

                        var debugRecord = new SysAttendanceRecord
                        {
                            ID = Guid.NewGuid(),
                            PersonId = personId,
                            ShiftDate = debugDate,
                            AttendanceShiftGroupId = request.AttendanceShiftGroupId,
                            ShiftType = ShiftTypeEnum.正常上班,
                            ScheduleType = ScheduleTypeEnum.人工排班,
                            Status = ShiftStatusEnum.正常,
                            AttendanceResult = attendanceResult,
                            IsAbnormal = isAbnormal,
                            LateMinutes = lateMinutes,
                            EarlyLeaveMinutes = earlyLeaveMinutes,
                            WorkMinutes = workMinutes,
                            MissingPunchCount = missingPunchCount,
                            StartTime = startTime,
                            EndTime = endTime
                        };
                        debugRecords.Add(debugRecord);
                    }

                    // 批量新增前30天的调试记录
                    if (debugRecords.Count > 0)
                    {
                        await DC.Set<SysAttendanceRecord>().AddRangeAsync(debugRecords);
                        await DC.SaveChangesAsync();
                    }
#endif

                    // 批量更新排班记录
                    if (updateRecordIds.Count > 0)
                    {
                        await DC.Set<SysAttendanceRecord>()
                            .Where(e => updateRecordIds.Contains(e.ID))
                            .ExecuteUpdateAsync(e => e
                                .SetProperty(r => r.AttendanceShiftGroupId, r => request.AttendanceShiftGroupId)
                                .SetProperty(r => r.ShiftType, ShiftTypeEnum.正常上班)
                                .SetProperty(r => r.ScheduleType, ScheduleTypeEnum.自动排班)
                                .SetProperty(r => r.UpdateBy, Wtm.LoginUserInfo.ITCode)
                                .SetProperty(r => r.UpdateTime, DateTime.Now));
                    }

                    // 批量新增排班记录
                    if (records.Count > 0)
                    {
                        await DC.Set<SysAttendanceRecord>().AddRangeAsync(records);
                        await DC.SaveChangesAsync();
                    }
                }
            }

            if (request.ShiftType == ShiftAction.正常上班)
            {
                // 仅处理已经计算考勤, 并且考勤异常的排班记录
                var records = await DC.Set<SysAttendanceRecord>()
                    .Include(e => e.Person)
                    .Where(x => request.PersonIds.Contains(x.PersonId.Value))
                    .Where(x => x.ShiftDate >= startDate && x.ShiftDate <= endDate)
                    .Where(x => x.AttendanceResult != AttendanceResultEnum.正常 &&
                                x.AttendanceResult != AttendanceResultEnum.未计算)
                    .Where(x => x.Status == ShiftStatusEnum.正常)
                    .ToListAsync();
                if (records.Any())
                {
                    records.ForEach(element =>
                    {
                        element.AttendanceResult = AttendanceResultEnum.正常;
                        element.UpdateBy = Wtm.LoginUserInfo.ITCode;
                        element.UpdateTime = DateTime.Now;
                        element.Remark = request.Remark;
                        element.IsAbnormal = false;
                    });
                    await DC.SaveChangesAsync();
                }
                else
                {
                    MSD.AddModelError(" ", $"没有找到异常考勤, 只能对已有考勤结果并且考勤异常的排班记录进行正常上班操作");
                    return false;
                }

                await DC.SaveChangesAsync();
            }

            if (request.ShiftType == ShiftAction.加班 && scheduleType == ScheduleTypeEnum.流程排班)
            {
                var bill = await DC.Set<SysDailyOvertimeRequestBill>()
                    .Include(e => e.Person)
                    .AsNoTracking()
                    .FirstOrDefaultAsync(e => e.ID == billId.Value);
                if (bill == null)
                {
                    MSD.AddModelError(" ", "加班申请单不存在");
                    return false;
                }

                var record = await DC.Set<SysAttendanceRecord>()
                    .FirstOrDefaultAsync(e => e.ID == bill.RecordId);
                if (record == null)
                {
                    MSD.AddModelError(" ", "加班申请单对应的排班记录不存在");
                    return false;
                }

                record.AttendanceResult = AttendanceResultEnum.加班;
                record.ScheduleType = ScheduleTypeEnum.流程排班;
                record.UpdateBy = "system";
                record.UpdateTime = DateTime.Now;
                record.Remark = request.Remark;
                await DC.SaveChangesAsync();
                return true;
            }

            return true;
        }
    }
}